import "@site/src/languages/highlight";
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Loading and Running Yarn Scripts

Welcome to the YarnRunner functionality tutorial. In this tutorial, we will guide you on how to load and run the Yarn narrative scripts you wrote in the [previous tutorial](/docs/tutorial/Writing%20Game%20Dialogue/introduction-to-yarn).

### 1. Initializing YarnRunner

<Tabs>
<TabItem value="yue" label="Yuescript">

First, make sure you have imported all the necessary modules.

```yue title="init.yue"
_ENV = Dora!
import "YarnRunner"
```

To ensure that we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:

```yue title="init.yue"
path = Path\getScriptPath ...
Content\insertSearchPath 1, path
```

Next, assuming we want to load a Yarn file named "tutorial.yarn" with a starting node titled "Start," you can write the following code:

```yue title="init.yue"
runner = YarnRunner "tutorial.yarn", "Start"
```

</TabItem>
<TabItem value="tl" label="Teal">

First, make sure you have correctly imported all the necessary modules. Here are the modules we need for the examples in this tutorial:

```tl title="init.tl"
local Content <const> = require("Content")
local Path <const> = require("Path")
local Node <const> = require("Node")
local Director <const> = require("Director")
local YarnRunner <const> = require("YarnRunner")
```

To ensure that we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:

```tl title="init.tl"
local path = Path:getScriptPath(...)
Content:insertSearchPath(1, path)
```

Next, assuming we want to load a Yarn file named "tutorial.yarn" with a starting node titled "Start," you can write the following code:

```tl title="init.tl"
local runner = YarnRunner("tutorial.yarn", "Start")
```

</TabItem>
<TabItem value="lua" label="Lua">

First, make sure you have correctly imported all the necessary modules. Here are the modules we need for the examples in this tutorial:

```lua title="init.lua"
local Content <const> = require("Content")
local Path <const> = require("Path")
local Node <const> = require("Node")
local Director <const> = require("Director")
local YarnRunner <const> = require("YarnRunner")
```

To ensure that we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:

```lua title="init.lua"
local path = Path:getScriptPath(...)
Content:insertSearchPath(1, path)
```

Next, assuming we want to load a Yarn file named "tutorial.yarn" with a starting node titled "Start," you can write the following code:

```lua title="init.lua"
local runner = YarnRunner("tutorial.yarn", "Start")
```

</TabItem>
</Tabs>

### 2. Executing and Displaying Narrative Content

We have defined an `advance` function that can read and display text content or options from the Yarn script. Depending on the narrative content, it can also display character names:

<Tabs>
<TabItem value="yue" label="Yuescript">

```yue title="init.yue"
-- The `advance` function takes an optional integer parameter representing the player's choice index.
-- When calling this function for the first time or when no choice is needed, we pass nil.
advance = (option)->

	-- The function first calls `runner\advance` to fetch the next part of the Yarn script.
	-- This returns two values: an action type and a result.
	action, result = runner\advance option

	-- Based on the action type, we choose how to handle the result.
	switch action when "Text"

		-- If the action is "Text," the result will be a TextResult object,
		-- which contains the text content and any associated marks (e.g., character names).
		-- We check for marks, extract the character name (if present), and print the text content.
		charName = ""
		if result.marks
			for mark in *result.marks
				switch mark when {name: attr, attrs: {:name}}
					charName = "#{name}: " if attr == "char"
		print charName .. result.text

	when "Option"

		-- If the action is "Option," the result will be an OptionResult object,
		-- which contains one or more options. The function iterates through these options and prints them,
		-- which the player can choose later.
		for i, op in ipairs result
			print "[#{i}]: #{op.text}" if op

	else

		-- For other actions (e.g., errors), the function directly prints the result.
		print result
```

</TabItem>
<TabItem value="tl" label="Teal">

```tl title="init.tl"
-- The `advance` function takes an optional integer parameter representing the player's choice index.
-- When calling this function for the first time or when no choice is needed, we pass nil.
local function advance(option?: integer)

	-- The function first calls `runner:advance(option)` to fetch the next part of the Yarn script.
	-- This returns two values: an action type and a result.
	local action, result = runner:advance(option)

	-- Based on the action type, we choose how to handle the result.
	if action == "Text" then

		-- If the action is "Text," the result will be a TextResult object,
		-- which contains the text content and any associated marks (e.g., character names).
		-- We check for marks, extract the character name (if present), and print the text content.
		local textResult = result as YarnRunner.TextResult

		-- Check for marks, extract character name (if present), and print text content.
		local characterName = ""
		local marks = textResult.marks
		if not (marks is nil) then
			for i = 1, #marks do
				local mark = marks[i]
				if mark.name == "char" then
					characterName = tostring(mark.attrs.name) .. ": "
				end
			end
		end
		print(characterName .. textResult.text)

	elseif action == "Option" then

		-- If the action is "Option," the result will be an OptionResult object,
		-- which contains one or more options. The function iterates through these options and prints them,
		-- which the player can choose later.
		local optionResult = result as YarnRunner.OptionResult
		for i, op in ipairs(optionResult) do
			if op and not (op is boolean) then
				print("[" .. tostring(i) .. "]: " .. op.text)
			end
		end

	else

		-- For other actions (e.g., errors), the function directly prints the result.
		print(result)

	end
end
```

</TabItem>
<TabItem value="lua" label="Lua">

```lua title="init.lua"
-- The `advance` function takes an optional integer parameter representing the player's choice index.
-- When calling this function for the first time or when no choice is needed, we pass nil.
local function advance(option)

	-- The function first calls `runner:advance(option)` to fetch the next part of the Yarn script.
	-- This returns two values: an action type and a result.
	local action, result = runner:advance(option)

	-- Based on the action type, we choose how to handle the result.
	if action == "Text" then

		-- If the action is "Text," the result will be a TextResult object,
		-- which contains the text content and any associated marks (e.g., character names).
		-- We check for marks, extract the character name (if present), and print the text content.
		local characterName = ""
		local marks = result.marks
		if marks then
			for i = 1, #marks do
				local mark = marks[i]
				if mark.name == "char" then
					characterName = mark.attrs.name .. ": "
				end
			end
		end
		print(characterName .. result.text)

	elseif action == "Option" then

		-- If the action is "Option," the result will be an OptionResult object,
		-- which contains one or more options. The function iterates through these options and prints them,
		-- which the player can choose later.
		for i, op in ipairs(result) do
			if op then
				print("[" .. tostring(i) .. "]: " .. op.text)
			end
		end

	else

		-- For other actions (e.g., errors), the function directly prints the result.
		print(result)

	end
end
```

</TabItem>
</Tabs>

### 3. Initiating the Narrative

To initiate the narrative, you simply call the `advance` function without any arguments:

<Tabs>
<TabItem value="yue" label="Yuescript">

```yue title="init.yue"
advance!
```

</TabItem>
<TabItem value="tl" label="Teal">

```tl title="init.tl"
advance()
```

</TabItem>
<TabItem value="lua" label="Lua">

```lua title="init.lua"
advance()
```

</TabItem>
</Tabs>

### 4. Responding to User Input

To allow player interaction with the narrative, we need a node to capture and respond to user input. We create a node and assign it a signal slot named "go." When this signal is triggered, it will call the `advance` function again and pass the player's choice:

<Tabs>
<TabItem value="yue" label="Yuescript">

```yue title="init.yue"
with Node!
	\gslot "go", (option)-> advance option
	\addTo Director.entry
```

</TabItem>
<TabItem value="tl" label="Teal">

```tl title="init.tl"
local node = Node()
node:gslot("go", function(option: nil | integer)
	advance(option)
end)
node:addTo(Director.entry)
```

</TabItem>
<TabItem value="lua" label="Lua">

```lua title="init.lua"
local node = Node()
node:gslot("go", function(option)
	advance(option)
end)
node:addTo(Director.entry)
```

</TabItem>
</Tabs>

In this example, a global event listener has been registered for quick testing. In actual game development, you would need to implement UI interaction logic. With the "go" global event listener, you can continue the dialogue by entering `emit 'go'` in the Dora SSR console command line, and you can interactively test the conversation by entering `emit 'go', 1` to select dialogue branches.

### 5. Conclusion

Now, you have set up all the necessary code to load and run Yarn narrative scripts. You can run the above scripts to start your interactive narrative, where players can interact by choosing options. Happy storytelling!
